﻿# シンガーソングの発音コンバータ。
#   エクセル→テーブルデータ
#

use strict;

use utf8;
BEGIN {
	unshift @INC, "..";
}
use Unicode::Japanese;
use Win32::OLE qw(in with CP_UTF8);
use Win32::OLE::Const 'Microsoft Excel';
use Cwd;

use voice_table;

$Win32::OLE::CP = CP_UTF8;

my $TRUE = 1;
my $FALSE = 0;

my $CATEGORY_SIZE = 22;
my $CATEGORY_MAX = $CATEGORY_SIZE - 1;
my @CATEGORY_NUM = (
	202, 27,109, 63, 42,
	 75, 63, 60, 69, 69,
	 69, 78, 45, 54, 45,
	 42, 36, 29,154,200,
	 33,251
);
my %PATH_PREFIX = (
	e => 'ENGLISH/',
	f => 'FRANCE/',
	g => 'GERMANY/',
	i => 'ITALY/',
	s => 'SPAIN/'
);
my $TMP = "temp12345.txt";
my $HIDE_TERM_NUM = 5;

my $SHEET_NAME = "Simpletext";
my $START_ROW = 2;
my $START_COL = "F";
my $JAPANESE_COL = "C";
my $NEW_COL = "E";
my $HIDE_SIMPLE_FILE_NAME = "EME_Simpletext_hide.xls";

my $voice_file_name;
my $open_simple_file_name;
my $hide_simple_file_name;
my %mark_to_no;
my ($excel, $open_book, $hide_book);
my $tmp_file;

main();
exit;

#-----------------------------------------------------------
# メイン。
#-----------------------------------------------------------
sub main {
	my @argv = @ARGV;
	my @pokemon;
	my @waza;
	my @other;
	my ($open_sheet, $hide_sheet, $range, $row, $col);
	my ($category, $mark, $japanese, $data, $new);
	our @NO_TO_MARK;

	if (@argv != 2) {
		usage();
		exit -1;
	}
	if (-e $TMP) {
		die "error: exist $TMP\n";
	}
	$voice_file_name = "../../../resource/LANG_" . $PATH_PREFIX{$argv[0]} . 'singeroyaji.dat';
	$open_simple_file_name = $argv[1];
	$hide_simple_file_name = getcwd() . "/" . $HIDE_SIMPLE_FILE_NAME;
	if ($argv[0] ne 'e') {
		$START_COL++;
		$NEW_COL++;
	}

	# 発音記号から発音番号を引くためのテーブル作成。
	for my $i (0 .. @NO_TO_MARK - 1) {
		$mark_to_no{$NO_TO_MARK[$i]} = $i;
	}

	# エクセルから必要なデータを取得する。
	$excel = open_excel();
	$open_book = get_book($excel, $open_simple_file_name);
	$open_sheet = get_sheet($open_book, $SHEET_NAME);
	$range = $open_sheet->Range("A65536")->End(xlUp);
	$category = $open_sheet->Range("A$START_ROW:$range->{Address}")->{Value};
	$col = add_to_str($START_COL, 5);
	$mark = $open_sheet->Range("$START_COL$START_ROW:$col$range->{Row}")->{Value};
	$japanese = $open_sheet->Range("$JAPANESE_COL$START_ROW:$JAPANESE_COL$range->{Row}")->{Value};

	$hide_book = get_book($excel, $hide_simple_file_name);
	$hide_sheet = get_sheet($hide_book, $SHEET_NAME);
	$range = $hide_sheet->Range("A65536")->End(xlUp);
	$col = add_to_str($START_COL, 6 * $HIDE_TERM_NUM - 1);
	$data = $hide_sheet->Range("$START_COL$START_ROW:$col$range->{Row}")->{Value};
	$new = $hide_sheet->Range("$NEW_COL$START_ROW:$NEW_COL$range->{Row}")->{Value};

	# エクセルからテーブルを構築する。
	$row = 0;
	for my $i (0 .. $CATEGORY_MAX) {
		my ($sub, $count, $kind);

		if ($i == 0 || $i == 21) {
			# ポケモン名。
			$kind = \@pokemon;
			$sub = \&make_table;
		} elsif ($i == 18 || $i == 19) {
			# わざ名。
			$kind = \@waza;
			$sub = \&make_table;
		} else {
			$other[$i] = [];
			$kind = $other[$i];
			$sub = \&make_table_other;
		}

		while (1) {
			my $value = $category->[$row][0];
			my ($category, $no, $col, $next);

			if ($value eq "") {
				last;
			}
			unless ($value =~ /^Category(\d\d)Strl?(\d+)$/) {
				die "error: format $open_simple_file_name, row = ", $row + $START_ROW, ", $value\n";
			}
			($category, $no) = ($1, $2);
			if ($category != $i) {
				last;
			}
			$sub->($no, $count, $row + $START_ROW, $value);
			$col = $START_COL;
			$next = 6;
			# 本当は、hide登録にあるものをハッシュにして、無いものについて
			# 採用するようにしたい。が、このように作ってしまったので、
			# “くさい”がこの方法でいく。
			if ($new->[$row][0] ne "*") {
				# 新規追加ワード分。
				for my $j (0 .. 5) {
					my $voice = $mark->[$row][$j];
					my $value;

					$voice =~ s/^\s+//;
					$voice =~ s/\s+$//;
					if ($voice eq "") {
						$next = $j;
						last;
					}
					$value = $mark_to_no{$voice};
					if (!defined($value)) {
						print "warning: mark row = ", $row + $START_ROW, ", col = $col\n";
						$col++;
						next;
					}
					if ($value != 17) {
						$kind->[$no]{voice}[$j] = [$value * 3, 0, 0, 0];
					} else {
						$kind->[$no]{voice}[$j] = [51, 0, 0, 0];
					}
					$col++;
				}
			} else {
				# ルビー・サファイアですでにあったワード。
				for my $j (0 .. 5) {
					my $voice = $data->[$row][$j * $HIDE_TERM_NUM];
					my $value;

					if ($voice ne $mark->[$row][$j]) {
						print "warning: different value = ", $row + $START_ROW, ", col = $col\n";
						$col++;
						next;
					}
					if ($voice eq "") {
						$next = $j;
						last;
					}
					$value = $mark_to_no{$voice};
					if (!defined($value)) {
						print "warning: mark row = ", $row + $START_ROW, ", col = $col\n";
						$col++;
						next;
					}
					$kind->[$no]{voice}[$j][0] = $value * 3 + $data->[$row][$j * $HIDE_TERM_NUM + 1] - 1;
					$kind->[$no]{voice}[$j][1] = $data->[$row][$j * $HIDE_TERM_NUM + 2];
					$kind->[$no]{voice}[$j][2] = $data->[$row][$j * $HIDE_TERM_NUM + 3];
					$kind->[$no]{voice}[$j][3] = $data->[$row][$j * $HIDE_TERM_NUM + 4];
					$col++;
				}
			}
			for my $j ($next .. 5) {
				my $voice = $mark->[$row][$j];

				$voice =~ s/^\s+//;
				$voice =~ s/\s+$//;
				if ($voice ne "") {
					print "warning: mark row = ", $row + $START_ROW, ", col = $col\n";
				}
				$col++;
			}
			$kind->[$no]{name} = $japanese->[$row][0];
			$kind->[$no]{name} =~ s/;$//;
			$row++;
			$count++;
		}
		if ($count != $CATEGORY_NUM[$i]) {
			print "warning: category $i num = $count\n";
		}
	}

	# 発音テーブルを出力する。
	open TMP, ">$TMP" or die "error: open $TMP\n";
	$tmp_file = \*TMP;
	f_print($tmp_file, '/* シンガーソングおやじ音程データ */' . "\n");
	# ポケモン名。
	f_print($tmp_file, "const int OyajiWordTblNumPokemon = " . scalar(@pokemon) . ";\n");
	out_table($tmp_file, \@pokemon, "Pokemon", 0);
	# わざ名。
	f_print($tmp_file, "const int OyajiWordTblNumWaza = " . scalar(@waza) . ";\n");
	out_table($tmp_file, \@waza, "Waza", 0);
	# その他。
	for my $i (1 .. 17, 20, 22 .. $CATEGORY_MAX) {
		out_table($tmp_file, $other[$i], sprintf("%02d", $i), $i);
	}
	f_print($tmp_file, 'static const TRVOICE * const OyajiWordTbl[] = {' . "\n");
	for my $i (0 .. $CATEGORY_MAX) {
		if ($i == 0 || $i == 18 || $i == 19 || $i == 21) {
			f_print($tmp_file, "\tNULL,\n");
		} else {
			f_print($tmp_file, sprintf("\tOyajiWordTbl%02d,\n", $i));
		}
	}
	f_print($tmp_file, "};\n");
	close($tmp_file);
	$tmp_file = undef;
	unlink($voice_file_name);
	rename($TMP, $voice_file_name) or die "error: rename from $TMP to $voice_file_name\n";
}

#-----------------------------------------------------------
# 使用方法。
#-----------------------------------------------------------
sub usage {
	my $com = $0;
	$com =~ s/.*\\//;

	print STDERR "\n";
	print STDERR "USAGE: $com <LANG> <simple text excel path>\n";
	print STDERR "LANG:\n";
	print STDERR "    e   - English\n";
	print STDERR "    f   - French\n";
	print STDERR "    g   - German\n";
	print STDERR "    i   - Italian\n";
	print STDERR "    s   - Spanish\n";
}

#-----------------------------------------------------------
# ファイル出力。
#-----------------------------------------------------------
sub f_print {
	my ($file, $str) = @_;

	print $file Unicode::Japanese->new($str)->sjis;
}

#-----------------------------------------------------------
# ポケモン名とわざ名に対して、テーブルを構築する。
#-----------------------------------------------------------
sub make_table {
	# ダミーです。
}

#-----------------------------------------------------------
# その他に対して、エクセルに挿入する。
#-----------------------------------------------------------
sub make_table_other {
	my ($no, $count, $row, $value) = @_;

	if ($no != $count) {
		die "error: number $open_simple_file_name, row = $row, $value\n";
	}
}

#-----------------------------------------------------------
# 文字のインクリメント加算。
#-----------------------------------------------------------
sub add_to_str {
	my ($str, $add) = @_;

	for my $i (0 .. $add - 1) {
		$str++;
	}

	return $str;
}

#-----------------------------------------------------------
# エクセルオープン。
#-----------------------------------------------------------
sub open_excel {
	my $excel;

	$excel = Win32::OLE->new('Excel.Application');
	if (!defined($excel)) {
		die "error: start Excel\n";
	}
	return $excel;
}

#-----------------------------------------------------------
# エクセルブック取得。
#-----------------------------------------------------------
sub get_book {
	my ($excel, $file_name) = @_;
	my $book;

	$book = $excel->Workbooks->Open($file_name);
	if (!defined($book)) {
		die "error: open $file_name\n";
	}
	return $book;
}

#-----------------------------------------------------------
# エクセルシート取得。
#-----------------------------------------------------------
sub get_sheet {
	my ($book, $sheet_name) = @_;
	my $sheet;

	$sheet = $book->Worksheets($sheet_name);
	if (!defined($sheet)) {
		die "error: get sheet $sheet_name\n";
	}
	return $sheet;
}

#-----------------------------------------------------------
# テーブル出力。
#-----------------------------------------------------------
sub out_table {
	my ($tmp, $kind, $name, $category_no) = @_;
	my $no;

	f_print($tmp, sprintf('static const TRVOICE OyajiWordTbl%s[] = {' . "\n", $name));
	$no = 0;
	for my $i (@{$kind}) {
		my $next;

		f_print($tmp, "\t{{");
		$next = 0;
		for my $j (@{$i->{voice}}) {
			f_print($tmp, sprintf("{%2d,%d,%d,%d}, ", $j->[0], $j->[1], $j->[2], $j->[3]));
			$next++;
		}
		for my $j ($next .. 5) {
			f_print($tmp, "{-1,0,0,0}, ");
		}
		f_print($tmp, "}},");
		if (defined($i->{name})) {
			f_print($tmp, sprintf("\t\t// %3d: %s\n", $no, $i->{name}));
		} else {
			f_print($tmp, sprintf("\t\t// %3d: none\n", $no));
		}
		$no++;
	}
	f_print($tmp, "};\n");
}

#-----------------------------------------------------------
# 終了処理。
#-----------------------------------------------------------
sub END {
	if (defined($open_book)) {
		$open_book->Close();
	}
	if (defined($hide_book)) {
		$hide_book->Close();
	}
	if (defined($excel)) {
		$excel->Quit();
	}
	if (defined($tmp_file)) {
		close($tmp_file);
		unlink($TMP);
	}
}
